package validate

import (
	"context"
	"gitee.com/bobo-rs/creative-services/enums"
	"gitee.com/bobo-rs/creative-services/framework/dao"
	"gitee.com/bobo-rs/creative-services/framework/model"
	"gitee.com/bobo-rs/creative-services/framework/service"
	"gitee.com/bobo-rs/creative-services/library/exception"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gvalid"
)

// RuleRegisterRbac 注册RBAC
func RuleRegisterRbac() {
	gvalid.RegisterRuleByMap(map[string]gvalid.RuleFunc{
		`depart-delete`:          RuleDepartDelete,
		`depart-exists-id`:       RuleDepartExistsById,
		`admin-exists-id`:        RuleAdminExistsId,
		`perm-exists-id`:         RulePermissionExistsId,
		`role-exists-id`:         RuleRolesExistsId,
		`assoc-role-exists-id`:   RuleAssocRolesExistsId,
		`depart-disable`:         RuleDepartmentDisable,
		`assoc-depart-exists-id`: RuleAssocDepartExistsId,
		`is-super-manage`:        RuleIsSuperManage,
		`set-manage-status`:      RuleAdminSetStatus,
		`invite-valid-id`:        RuleInviteValidById,
		`invite-exists-id`:       RuleInviteExistsById,
		`invite-delete-id`:       RuleInviteDeleteById,
		`invite-valid-token`:     RuleInviteValidByToken,
		`invite-auth-token`:      RuleInviteAuthByToken,
	})
}

// RuleDepartDelete 检测部门删除规则
func RuleDepartDelete(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return exception.New(`部门ID不能为空`)
	}

	// 检测是否含有部门人员
	if service.Rbac().CheckAdminDepartByDepartId(ctx, in.Value.Uint()) {
		return exception.New(`该部门含有员工，请迁移后再操作删除`)
	}

	// 检测是否含有子级部门
	if service.Rbac().CheckChildDepartByDepartId(ctx, in.Value.Uint()) {
		return exception.New(`含有未迁移的子级部门，请迁移后再删除`)
	}
	return nil
}

// RuleDepartExistsById 检测部门是否存在
func RuleDepartExistsById(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}
	// 检测部门是否存在
	if !service.Rbac().CheckDepartmentById(ctx, in.Value.Uint()) {
		return exception.New(`部门不存在`)
	}
	return nil
}

// RuleAdminExistsId 检测管理员是否存在
func RuleAdminExistsId(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}
	// 管理员是否存在
	if !service.Rbac().CheckAdminExistsId(ctx, in.Value.Uint()) {
		return exception.New(`管理员不存在`)
	}
	return nil
}

// RulePermissionExistsId 检测权限是否存在
func RulePermissionExistsId(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}
	// 检测权限是否存在
	if !service.Rbac().CheckPermissionsExistsById(ctx, in.Value.Uint()) {
		return exception.New(`权限不存在`)
	}
	return nil
}

// RuleRolesExistsId 角色是否存在
func RuleRolesExistsId(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}
	// 角色是否存在
	if !service.Rbac().CheckRolesExistsById(ctx, in.Value.Uint()) {
		return exception.New(`角色不存在`)
	}
	return nil
}

// RuleAssocRolesExistsId 验证关联的角色ID是否存在
func RuleAssocRolesExistsId(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.Uints()) == 0 {
		return nil
	}

	// 验证角色是否存在
	if len(in.Value.Uints()) != service.Rbac().RolesTotalById(ctx, in.Value.Uints()...) {
		return exception.New(`关联角色不存在`)
	}
	return nil
}

// RuleAssocDepartExistsId 验证关联的部门ID是否存在
func RuleAssocDepartExistsId(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.Uints()) == 0 {
		return nil
	}

	// 验证关联部门是否存在
	total, _ := service.Rbac().DepartmentModel().Total(ctx, g.Map{
		dao.Department.Columns().Id: in.Value.Uints(),
	})
	if len(in.Value.Uints()) != total {
		return exception.New(`关联部门不存在`)
	}
	return nil
}

// RuleDepartmentDisable 检测部门是否被禁用
func RuleDepartmentDisable(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}

	// 获取部门信息
	var detail model.DepartmentItem
	err := service.Rbac().DepartmentModel().Scan(ctx, g.Map{
		dao.Department.Columns().Id: in.Value.Uint(),
	}, &detail)
	if err != nil {
		return exception.New(`部门不存在`)
	}

	// 若是禁用则，则验证子级是否存在
	if detail.Status == uint(enums.DepartStatusOk) {
		total, _ := service.Rbac().DepartmentModel().Total(ctx, g.Map{
			dao.Department.Columns().Pid:    detail.Id,
			dao.Department.Columns().Status: enums.DepartStatusOk,
		})
		if total > 0 {
			return exception.New(`请禁用下级部门，才能禁用本部门`)
		}
	}
	return nil
}

// RuleIsSuperManage 验证是否超级管理员
func RuleIsSuperManage(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}
	// 是否超管用户
	admAuth := service.User().GetAdminUser(ctx)
	if admAuth.IsSuperManage == uint(enums.AdminIsSuperMangeOrdinary) {
		return exception.New(`当前管理员非超管，该操作只允许超管可以执行`)
	}

	// 不能自己操作自己
	if admAuth.Id == in.Value.Uint() {
		return exception.New(`超管用户不能更改自己状态`)
	}

	// 当前用户不存在
	if !service.Rbac().CheckAdminExistsId(ctx, in.Value.Uint()) {
		return exception.New(`当前管理员不存在`)
	}
	return nil
}

// RuleAdminSetStatus 设置管理员状态
func RuleAdminSetStatus(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}

	// 获取管理员信息
	var detail model.UserAdminDetailItem
	err := service.Rbac().ProcessAdminDetailByAid(
		ctx, in.Value.Uint(), &detail,
	)
	if err != nil {
		return err
	}

	// 获取当前登录信息
	admAuth := service.User().GetAdminUser(ctx)
	if admAuth.Id == detail.Id {
		return exception.New(`管理员状态操作不能更改自己状态`)
	}

	// 验证当前用户是否超管-非超管用户不能允许操作超管用户状态
	if detail.IsSuperManage == uint(enums.AdminIsSuperMangeOrdinary) {
		// 非超管用户
		return nil
	}

	// 当前操作用户非超管
	if admAuth.IsSuperManage == uint(enums.AdminIsSuperMangeOrdinary) {
		return exception.New(`不能更改超管用户状态`)
	}

	return nil
}

// RuleInviteExistsById 通过邀请ID检测邀请是否存在
func RuleInviteExistsById(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}
	// 是否存在
	if b, _ := service.Rbac().InviteModel().ExistsPri(ctx, in.Value.Uint()); !b {
		return exception.New(`邀请信息不存在`)
	}
	return nil
}

// RuleInviteValidById 通过邀请ID验证是否属于有效（非已注册和已撤销）
func RuleInviteValidById(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}
	// 获取邀请信息
	detail, err := service.Rbac().GetInviteValidDetailById(ctx, in.Value.Uint())
	if err != nil {
		return exception.Newf(`邀请信息不存在%s`, err.Error())
	}
	// 是否已注册和已撤销
	if status := enums.AdminInviteStatus(detail.Status); status != enums.AdminInviteStatusZero {
		return exception.New(status.Fmt())
	}
	return nil
}

// RuleInviteDeleteById 通过邀请ID验证是否可以删除
func RuleInviteDeleteById(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.Uint() == 0 {
		return nil
	}
	// 获取邀请信息
	detail, err := service.Rbac().GetInviteValidDetailById(ctx, in.Value.Uint())
	if err != nil {
		return exception.Newf(`邀请信息不存在%s`, err.Error())
	}
	// 是否已注册
	if status := enums.AdminInviteStatus(detail.Status); status == enums.AdminInviteStatusOne {
		return exception.New(status.Fmt())
	}
	return nil
}

// RuleInviteValidByToken 验证邀请Token是否有效
func RuleInviteValidByToken(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.IsEmpty() {
		return nil
	}
	// 是否有效
	return service.Rbac().CheckInviteValidByToken(ctx, in.Value.String())
}

// RuleInviteAuthByToken 通过邀请Token授权邀请为管理员-登录中
func RuleInviteAuthByToken(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.IsEmpty() {
		return nil
	}

	// 获取用户ID
	uid := service.BizCtx().GetUid(ctx)
	if uid == 0 {
		return exception.NewCode(enums.ErrorNotLogoutIn, ``)
	}

	// 是否已是管理员
	if service.Rbac().CheckAdminExistsByUid(ctx, uid) {
		return exception.NewCode(enums.ErrorInviteIn, ``)
	}
	return nil
}
